package condition;

import java.util.Collection;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class LockConditionTest {


  public static void main(String[] args) {
    Counter counter = new Counter();

    Thread t1 = new Thread(new CountRunnable(counter));
    Thread t2 = new Thread(new CountRunnable(counter));
    Thread t3 = new Thread(new CountRunnable(counter));
    Thread t4 = new Thread(new CountRunnable(counter));
    t1.start();
    t2.start();
    t3.start();
    t4.start();

    counter.lock.interruptWaiters(counter.con);

  }


  public static class Counter {

    public InterruptibleReentrantLock lock = new InterruptibleReentrantLock();

    private int count = 0;

    public Condition con = lock.newCondition();

    public void test() throws InterruptedException {
      lock.lock();
      try {
        count++;
        System.out.println("count:" + count);
        con.await();

      } finally {
        lock.unlock();
      }

    }
  }


  public static class CountRunnable implements Runnable {

    public Counter counter;

    public CountRunnable(Counter counter) {
      this.counter = counter;
    }

    @Override
    public void run() {
      try {
        counter.test();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  static class InterruptibleReentrantLock extends ReentrantLock {

    private static final long serialVersionUID = 1L;

    /**
     * Create a new InterruptibleReentrantLock with the given fairness policy.
     *
     * @param fairness true means threads should acquire contended locks as if
     * waiting in a FIFO queue
     */
//    public InterruptibleReentrantLock(final boolean fairness) {
//      super(fairness);
//    }

    /**
     * Interrupt the threads that are waiting on a specific condition
     *
     * @param condition the condition on which the threads are waiting.
     */
    public void interruptWaiters(final Condition condition) {
      final Collection<Thread> threads = getWaitingThreads(condition);
      for (final Thread thread : threads) {
//        thread.interrupt();
        System.out.println(thread.getName() + ":" + thread.getId());
      }
    }
  }

}
